package com.fubowen.lepton.ui.container.children.bookmark

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.CheckBox
import androidx.fragment.app.Fragment
import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.DefaultItemAnimator
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.recyclerview.widget.SortedList
import com.fubowen.lepton.R
import com.fubowen.lepton.bean.BookmarkBean
import com.fubowen.lepton.bean.Home
import com.fubowen.lepton.bean.Password
import com.fubowen.lepton.databinding.FragmentBookmarkBinding
import com.fubowen.lepton.databinding.FragmentBookmarkContextMenuBinding
import com.fubowen.lepton.extension.any
import com.fubowen.lepton.extension.digest
import com.fubowen.lepton.extension.filter
import com.fubowen.lepton.extension.forEach
import com.fubowen.lepton.extension.moveToPrivacy
import com.fubowen.lepton.helper.DBHelper
import com.fubowen.lepton.helper.IntentHelper.shareSite
import com.fubowen.lepton.helper.ViewHelper.confirm
import com.fubowen.lepton.helper.ViewHelper.findViewsByTag
import com.fubowen.lepton.helper.ViewHelper.password
import com.fubowen.lepton.helper.ViewHelper.prompt
import com.fubowen.lepton.helper.ViewHelper.setIcon
import com.fubowen.lepton.helper.ViewHelper.setVisible
import com.fubowen.lepton.helper.ViewHelper.toast
import com.fubowen.lepton.helper.ViewHelper.writeTextToClipboard
import com.fubowen.lepton.ui.container.ManagerFragmentDirections
import com.fubowen.lepton.ui.container.children.bookmark.recycler.BookmarkAdapter
import com.fubowen.lepton.ui.container.children.bookmark.recycler.BookmarkSortedListAdapterCallback
import com.fubowen.lepton.ui.container.children.bookmark.recycler.listener.OnItemClickListener
import com.google.android.material.bottomsheet.BottomSheetDialog
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import java.util.concurrent.atomic.AtomicInteger


class BookmarkFragment : Fragment() {

    private lateinit var binding: FragmentBookmarkBinding
    private lateinit var sortedList: SortedList<BookmarkBean>
    private lateinit var recycler: RecyclerView
    private var adapter = BookmarkAdapter()
    private lateinit var layoutManager: LinearLayoutManager

    private var isCheckAll = false
    private var selectable = false
    private var id = 0
    private var activated: View? = null

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        binding = FragmentBookmarkBinding.inflate(inflater, container, false)
        sortedList =
            SortedList(BookmarkBean::class.java, BookmarkSortedListAdapterCallback(adapter))
        recycler = binding.bookmarkRecycler
        layoutManager = recycler.layoutManager as LinearLayoutManager
        recycler.setItemViewCacheSize(30)
        recycler.setHasFixedSize(true)
        recycler.adapter = adapter
        val itemAnimator = DefaultItemAnimator().apply {
            supportsChangeAnimations = false
        }
        recycler.itemAnimator = itemAnimator
        adapter.setDataSource(sortedList)
        initBottomMenuListener()
        id = arguments?.getInt("id") ?: 0
        CoroutineScope(Dispatchers.Main).launch {
            DBHelper.db.bookmarkDao().getByParentIdFlow(id).collect { value ->
                sortedList.replaceAll(value)
                setBottomMenuState()
            }
        }
        adapter.setOnItemClickListener(itemClickListener())
        return binding.root
    }

    private fun initBottomMenuListener() {
        binding.bookmarkCheckAll.setOnClickListener {
            isCheckAll = !isCheckAll
            sortedList.forEach {
                it.selectable = true
                it.isSelected = isCheckAll
            }
            selectable = true
            setBottomMenuState()
        }
        binding.bookmarkGroup.setOnClickListener {
            val checkedList = sortedList.filter { it.isSelected }
            if (checkedList.isEmpty()) {
                binding.root.toast("您没有选择任何项目", 3000)
            } else {
                val controller = findNavController()
                val ids = checkedList.map { it.id }.joinToString(",")
                var action =
                    ManagerFragmentDirections.actionManagerFragmentToBookmarkGroupFragment(
                        ids,
                        checkedList[0].parentId
                    )
                if (id != 0) {
                    action =
                        BookmarkGroupPreviewFragmentDirections.actionBookmarkGroupPreviewFragmentToBookmarkGroupFragment(
                            ids,
                            checkedList[0].parentId
                        )
                }
                controller.navigate(action)
                reset()
            }
        }
        binding.bookmarkDelete.setOnClickListener {
            CoroutineScope(Dispatchers.Main).launch {
                val ids = ArrayList<Int>()
                val integer = AtomicInteger()
                val checkedList = sortedList.filter { it.isSelected }
                deleteTree(checkedList, ids, integer)
                requireContext().confirm(R.string.delete_tip, checkedList.size) {
                    DBHelper.db.bookmarkDao().del(ids)
                    setBottomMenuState()
                    reset()
                }
            }
        }
        binding.bookmarkEdit.setOnClickListener {
            selectable = !selectable
            if (selectable) {
                sortedList.forEach { it.selectable = selectable }
            } else {
                sortedList.forEach {
                    it.selectable = selectable
                    it.isSelected = false
                }
                isCheckAll = false
                binding.bookmarkCheckedGroup.setVisible(false)
                binding.bookmarkClearAll.setVisible(true)
            }
        }
        binding.bookmarkClearAll.setOnClickListener {
            requireContext().confirm(R.string.delete_tip, sortedList.size()) {
                CoroutineScope(Dispatchers.IO).launch {
                    DBHelper.db.bookmarkDao().clear()
                    setBottomMenuState()
                    reset()
                }
            }
        }
    }

    private fun setBottomMenuState() {
        if (sortedList.size() == 0) {
            binding.bookmarkClearAll.isEnabled = false
            binding.bookmarkEdit.isEnabled = false
            binding.bookmarkCheckAll.isEnabled = false
            binding.bookmarkGroup.setVisible(false)
        } else {
            binding.bookmarkClearAll.isEnabled = true
            binding.bookmarkEdit.isEnabled = true
            binding.bookmarkCheckAll.isEnabled = true
            val hasChecked = sortedList.any { it.isSelected }
            binding.bookmarkCheckedGroup.setVisible(hasChecked)
            binding.bookmarkClearAll.setVisible(!hasChecked)
        }
    }

    private fun reset() {
        selectable = false
        isCheckAll = false
        sortedList.forEach {
            it.selectable = selectable
            it.isSelected = selectable
        }
    }

    private fun itemClickListener() = object : OnItemClickListener {

        override fun onSelectableClick(itemView: View, sender: View) {
            val position = layoutManager.getPosition(itemView)
            val item = sortedList.get(position)
            item.isSelected = (sender as CheckBox).isChecked
            if (!item.isSelected) isCheckAll = false
            setBottomMenuState()
        }

        override fun onToTopClick(itemView: View, sender: View) = toTop(itemView)

        override fun onItemClick(itemView: View) {
            val position = layoutManager.getPosition(itemView)
            val item = sortedList.get(position)
            if (selectable) {
                item.isSelected = !item.isSelected
                if (!item.isSelected) isCheckAll = false
                sortedList.updateItemAt(position, item)
                return
            }

            when (item.type) {
                BookmarkBean.TYPE_URL -> {
                    if (item.password.isNullOrBlank()) {
                        openUrl(item)
                    } else {
                        context?.prompt(R.string.bookmark_private_input_tip) { pwd ->
                            if (item.password == pwd.digest()) {
                                openUrl(item)
                                Pair(true, 0)
                            } else {
                                Pair(false, R.string.bookmark_password_error_tip)
                            }
                        }
                    }
                }

                BookmarkBean.TYPE_FOLDER -> openGroup(item)
            }
        }

        override fun onMoreMenuClick(itemView: View, sender: View) {
            activated = itemView
            bottomPopupWindow.value.show()
        }
    }

    private fun openUrl(item: BookmarkBean) {
        val action = if (id == 0)
            ManagerFragmentDirections.actionManagerFragmentToSearchListItemDetailFragment(
                searchText = item.title,
                url = item.url!!
            )
        else BookmarkGroupPreviewFragmentDirections.actionBookmarkGroupPreviewFragmentToSearchListItemDetailFragment(
            searchText = item.title,
            url = item.url!!
        )
        findNavController().navigate(action)
    }

    private fun openGroup(item: BookmarkBean) {
        val action = if (id == 0)
            ManagerFragmentDirections.actionManagerFragmentToBookmarkGroupPreviewFragment(
                title = item.title,
                id = item.id
            )
        else BookmarkGroupPreviewFragmentDirections.actionBookmarkGroupPreviewFragment(
            title = item.title,
            id = item.id
        )
        findNavController().navigate(action)
    }

    private fun deleteTree(list: List<BookmarkBean>, ids: ArrayList<Int>, counter: AtomicInteger) {
        list.forEach {
            when (it.type) {
                BookmarkBean.TYPE_URL -> {
                    ids.add(it.id)
                    counter.incrementAndGet()
                }

                BookmarkBean.TYPE_FOLDER -> {
                    ids.add(it.id)
                    val children = DBHelper.db.bookmarkDao().getByParentId(it.id)
                    if (children.isNotEmpty()) {
                        deleteTree(children, ids, counter)
                    }
                }
            }
        }
    }

    private fun toTop(root: View) {
        val position = layoutManager.getPosition(root)
        val item = getItem(root)
        item.topping = System.currentTimeMillis()
        CoroutineScope(Dispatchers.IO).launch {
            DBHelper.db.bookmarkDao().put(item)
            sortedList.updateItemAt(position, item)
        }
    }

    private fun getItem(view: View): BookmarkBean {
        val position = layoutManager.getPosition(view)
        return sortedList.get(position)
    }

    private fun bottomPopupWindowClickHandler(id: Int, itemView: View) {
        val item = getItem(itemView)
        when (id) {
            R.id.context_menu_to_top -> toTop(itemView)

            R.id.context_menu_delete -> {
                CoroutineScope(Dispatchers.IO).launch { DBHelper.db.bookmarkDao().del(item) }
            }

            R.id.context_menu_copy -> {
                context?.writeTextToClipboard(item.title, item.url)
                binding.root.toast(R.string.copy_tip, 3000)
            }

            R.id.context_menu_share -> {
                bottomPopupWindow.value.hide()
                this.shareSite(item.title, item.url)
            }

            R.id.context_menu_edit -> {
                val action =
                    ManagerFragmentDirections.actionManagerFragmentToBookmarkEditFragment(
                        id = item.id,
                        title = item.title,
                        url = item.url,
                        parentId = item.parentId
                    )
                findNavController().navigate(action)
            }

            R.id.context_menu_open_window -> {
                val action =
                    ManagerFragmentDirections.actionManagerFragmentToSearchListItemDetailFragment(
                        searchText = item.title,
                        url = item.url ?: "",
                    )
                findNavController().navigate(action)
            }

            R.id.context_menu_lock -> {
                context?.moveToPrivacy(
                    title = item.title,
                    source = Password.SOURCE_BOOKMARK,
                    data = item.url
                ) {
                    binding.root.toast("已成功放入密码箱", 3000)
                    CoroutineScope(Dispatchers.IO).launch {
                        DBHelper.db.bookmarkDao().del(item)
                    }
                }
            }

            R.id.context_menu_private -> {
                if (item.password.isNullOrBlank()) {
                    requireContext().prompt(R.string.bookmark_private_tip) { msg ->
                        if (msg.isBlank()) {
                            Pair(false, 0)
                        } else {
                            CoroutineScope(Dispatchers.IO).launch {
                                item.password = msg.digest()
                                DBHelper.db.bookmarkDao().put(item)
                            }
                            Pair(true, 0)
                        }
                    }
                } else {
                    requireContext().password(
                        R.string.update_password,
                        item.password
                    ) { new, _ ->
                        CoroutineScope(Dispatchers.IO).launch {
                            item.password = new.digest()
                            DBHelper.db.bookmarkDao().put(item)
                        }
                        Pair(true, 0)
                    }
                }
            }

            R.id.context_menu_home -> {
                CoroutineScope(Dispatchers.IO).launch {
                    DBHelper.db.homeDao().setOrIgnore(
                        Home(
                            icon = item.icon,
                            iconSource = item.iconSource,
                            data = item.url
                        )
                    )
                }
                binding.root.toast(R.string.bookmark_home_tip, 3000)
            }
        }
    }

    private val bottomPopupWindow = lazy {
        BottomSheetDialog(requireContext()).apply {
            val binding = FragmentBookmarkContextMenuBinding.inflate(layoutInflater)
            val viewList = binding.root.findViewsByTag("button")
            if (viewList.isNotEmpty()) {
                for (view in viewList) {
                    view.setOnClickListener {
                        activated?.let { view ->
                            bottomPopupWindowClickHandler(it.id, view)
                            this.hide()
                        }
                    }
                }
            }
            setOnShowListener {
                val item = getItem(activated!!)
                binding.contextMenuTitle.text = item.title
                binding.contextMenuIcon.setIcon(item.icon, item.iconSource)
                if (item.type == BookmarkBean.TYPE_FOLDER) {
                    binding.contextMenuUrl.text =
                        getString(R.string.bookmark_group_count_tip, item.childCount)
                    binding.contextMenuUrlPrivate.setVisible(false)
                } else {
                    binding.contextMenuUrl.text = item.host
                    binding.contextMenuUrlPrivate.setVisible(true)
                }
            }
            this.setContentView(binding.root)
        }
    }
}